package com.simple.trade.service.vm.impl;

import com.google.common.base.Preconditions;
import com.simple.common.entity.ReqContext;
import com.simple.common.entity.ResData;
import com.simple.common.entity.constant.Payment;
import com.simple.common.entity.dto.pay.vm.CardInfo;
import com.simple.common.entity.dto.pay.vm.DirectPayDto;
import com.simple.common.entity.dto.pay.vm.DirectPayRspDto;
import com.simple.common.entity.dto.pay.vm.VmBaseDto;
import com.simple.common.entity.po.sys.ChannelComp;
import com.simple.common.entity.po.sys.Product;
import com.simple.common.entity.po.sys.Trade;
import com.simple.common.entity.req.vm.pay.DirectPayReqV1;
import com.simple.common.entity.req.vm.pay.PayBase;
import com.simple.common.utils.RSAUtil;
import com.simple.common.entity.vo.pay.DirectResV1;
import com.simple.trade.service.vm.DirectPayV1Service;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.net.URLEncoder;

/**
 * @author yasud
 * @date 2020年09月22日 15:42
 * @description
 */
@Service
@Slf4j
public class DirectPayV1ServiceImpl extends PayBaseService<DirectResV1, DirectPayRspDto> implements DirectPayV1Service {

    @Value("${simple.publicKey}")
    String publicKey;

    /**
     * 直连支付v1
     *
     * @param req
     * @return
     */
    @Override
    public ResData<DirectResV1> directPayV1(DirectPayReqV1 req) {
        ResData<DirectResV1> res = pay(req, trade -> {
            trade.setCardHolder(req.getFirstName() + "_" + req.getLastName());
            trade.setCardExYear(Mono.fromCallable(() -> RSAUtil.encryptByPublicKey(req.getExpireYear(), publicKey)).block());
            trade.setCardExMonth(Mono.fromCallable(() -> RSAUtil.encryptByPublicKey(req.getExpireMonth(), publicKey)).block());
            trade.setCardCvv(Mono.fromCallable(() -> RSAUtil.encryptByPublicKey(req.getCvv(), publicKey)).block());
            trade.setCardNo(Mono.fromCallable(() -> RSAUtil.encryptByPublicKey(req.getCardNo(), publicKey)).block());
        }, Payment.PAY_TYPE.VM_DIRECT_PAY_V1);
        return res;
    }


    /**
     * 获取dto
     *
     * @param trade
     * @param reqContext
     * @param payBase
     * @param channel
     * @param product
     * @return
     */
    @Override
    public VmBaseDto getDto(Trade trade, ReqContext reqContext, PayBase payBase, ChannelComp channel, Product product) {
        DirectPayReqV1 directPayReqV1 = (DirectPayReqV1) payBase;
        CardInfo cardInfo = CardInfo.builder()
                .cardFristName(directPayReqV1.getFirstName())
                .cardLastName(directPayReqV1.getLastName())
                .cardExMonth(directPayReqV1.getExpireMonth())
                .cardExYear(directPayReqV1.getExpireYear())
                .cardCvv(directPayReqV1.getCvv())
                .cardNo(directPayReqV1.getCardNo())
                .build();
        DirectPayDto directPayDto = DirectPayDto.generateDto(trade, reqContext, payBase.getExtraInfo(), channel, product, cardInfo);
        return directPayDto;
    }

    /**
     * 结果转化
     *
     * @param rsp
     * @return
     */
    @Override
    protected DirectResV1 map(DirectPayRspDto rsp) {
        return generateRsp(rsp);
    }

    /**
     * 创建直连支付v1返回
     *
     * @param rspDto
     * @return
     */
    @SneakyThrows
    private DirectResV1 generateRsp(DirectPayRspDto rspDto) {
        Trade trade = rspDto.getTrade();
        Preconditions.checkNotNull(trade, "支付失败渠道服务错误，交易不能为空");
        DirectResV1 directResV1 = new DirectResV1();
        directResV1.setSerialNo(trade.getId());
        directResV1.setOrderNo(trade.getMerchantOrderNo());
        directResV1.setAmount(trade.getAmount());
        directResV1.setCurrency(trade.getCurrency());
        Preconditions.checkNotNull(rspDto.getPayType(), "支付失败渠道服务错误，返回直连支付类型不能为空");
        directResV1.setPayType(rspDto.getPayType());
        directResV1.setPayMsg(trade.getMsg());
        if (StringUtils.isNotBlank(rspDto.getPayHtml())) {
            directResV1.setPayHtml(URLEncoder.encode(rspDto.getPayHtml(), "UTF-8"));
        } else {
            directResV1.setPayHtml("");
        }
        if (StringUtils.isNotBlank(rspDto.getPaymentUrl())) {
            directResV1.setPayUrl(URLEncoder.encode(rspDto.getPaymentUrl(), "UTF-8"));
        } else {
            directResV1.setPayUrl("");
        }
        directResV1.setRemark(trade.getOrderDesc());
        directResV1.setPayStatus(trade.getStatus());
        return directResV1;
    }
}
